All files / local indexeddb_remote_document_cache.ts

96.97% Statements 32/33
90% Branches 9/10
100% Functions 11/11
96.67% Lines 29/30
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104                                  2x 2x   2x   2x         2x   2x 341x   2x       562x           2x       60x     1683x       1683x     1683x           125x       125x       125x 125x 125x   83x 83x 1x 82x 47x     125x   2x               2430x 2430x                 2305x    
/**
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
import { Query } from '../core/query';
import { DocumentMap, documentMap } from '../model/collections';
import { Document, MaybeDocument } from '../model/document';
import { DocumentKey } from '../model/document_key';
import { fail } from '../util/assert';
 
import { DbRemoteDocument, DbRemoteDocumentKey } from './indexeddb_schema';
import { LocalSerializer } from './local_serializer';
import { PersistenceTransaction } from './persistence';
import { PersistencePromise } from './persistence_promise';
import { RemoteDocumentCache } from './remote_document_cache';
import { SimpleDbStore, SimpleDbTransaction } from './simple_db';
 
export class IndexedDbRemoteDocumentCache implements RemoteDocumentCache {
  constructor(private serializer: LocalSerializer) {}
 
  addEntry(
    transaction: PersistenceTransaction,
    maybeDocument: MaybeDocument
  ): PersistencePromise<void> {
    return remoteDocumentsStore(transaction).put(
      dbKey(maybeDocument.key),
      this.serializer.toDbRemoteDocument(maybeDocument)
    );
  }
 
  removeEntry(
    transaction: PersistenceTransaction,
    documentKey: DocumentKey
  ): PersistencePromise<void> {
    return remoteDocumentsStore(transaction).delete(dbKey(documentKey));
  }
 
  getEntry(
    transaction: PersistenceTransaction,
    documentKey: DocumentKey
  ): PersistencePromise<MaybeDocument | null> {
    return remoteDocumentsStore(transaction)
      .get(dbKey(documentKey))
      .next(dbRemoteDoc => {
        return dbRemoteDoc
          ? this.serializer.fromDbRemoteDocument(dbRemoteDoc)
          : null;
      });
  }
 
  getDocumentsMatchingQuery(
    transaction: PersistenceTransaction,
    query: Query
  ): PersistencePromise<DocumentMap> {
    let results = documentMap();
 
    // Documents are ordered by key, so we can use a prefix scan to narrow down
    // the documents we need to match the query against.
    const startKey = query.path.toArray();
    const range = IDBKeyRange.lowerBound(startKey);
    return remoteDocumentsStore(transaction)
      .iterate({ range }, (key, dbRemoteDoc, control) => {
        const maybeDoc = this.serializer.fromDbRemoteDocument(dbRemoteDoc);
        if (!query.path.isPrefixOf(maybeDoc.key.path)) {
          control.done();
        } else if (maybeDoc instanceof Document && query.matches(maybeDoc)) {
          results = results.insert(maybeDoc.key, maybeDoc);
        }
      })
      .next(() => results);
  }
}
 
/**
 * Helper to get a typed SimpleDbStore for the remoteDocuments object store.
 */
function remoteDocumentsStore(
  txn: PersistenceTransaction
): SimpleDbStore<DbRemoteDocumentKey, DbRemoteDocument> {
  Eif (txn instanceof SimpleDbTransaction) {
    return txn.store<DbRemoteDocumentKey, DbRemoteDocument>(
      DbRemoteDocument.store
    );
  } else {
    return fail('Invalid transaction object provided!');
  }
}
 
function dbKey(docKey: DocumentKey): DbRemoteDocumentKey {
  return docKey.path.toArray();
}